feat(server-utils): Rewrite SentryLangChainInstrumentation to orchestrion#22266
Conversation
size-limit report 📦
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6abf5e8. Configure here.
| diagnosticsChannel.tracingChannel<EmbeddingsChannelContext>(channelName), | ||
| data => createEmbeddingsSpan(data, options), | ||
| { captureError: () => ({ mechanism: { handled: false, type: 'auto.ai.langchain' } }) }, | ||
| ); |
There was a problem hiding this comment.
Embedding errors double-reported
Medium Severity
The orchestrion LangChain embeddings binding enables captureError on bindTracingChannelToSpan, so rejected embedding calls call captureException while the underlying LangChain error still propagates to the caller. That can produce duplicate Sentry error events alongside the global unhandled-rejection path, unlike other orchestrion gen-AI channel integrations that omit captureError.
Triggered by project rule: PR Review Guidelines for Cursor Bot
Reviewed by Cursor Bugbot for commit 6abf5e8. Configure here.
| ); | ||
|
|
||
| // Embeddings have no shared concrete method on the base class (each provider implements | ||
| // `embedQuery`/`embedDocuments`), so they're hooked per provider. Only `@langchain/openai` is wired |
There was a problem hiding this comment.
m: do we also only support openai in the otel path?
There was a problem hiding this comment.
Good catch, I wasn't sure how to do the others since unlike RITM/IITM we need exact matchers for the other providers and also need to check their implementations as it seems like not all 6 providers have the same capabilities.
Also some inherit from one another like Google's so it would cause double instrumentation. I had a clanker do it just now and document these cases.
9c28a7a to
25b5c5c
Compare
25b5c5c to
e90583e
Compare
| // before any LangChain call still gets its own span — matches the OTel patch-on-import timing. It | ||
| // also stops the underlying SDK from double-instrumenting embeddings, whose `embedQuery`/ | ||
| // `embedDocuments` call the provider SDK (e.g. `openai`) internally. | ||
| function markProvidersSkipped(): void { |
There was a problem hiding this comment.
actually I just noticed that we have this here. we don't wanna do this anymore and I'll properly fix this in the iitm instrumentation as well so we don't get double spans. could you remove this please before merging? or else let me know then I'll do a follow up
There was a problem hiding this comment.
Yea I will drop it before merging
Rewrites the LangChain integration to a diagnostics-channel listener instead of `InstrumentationBase`, with orchestrion injecting the channels. Chat models are hooked once on `@langchain/core`'s `BaseChatModel` (`invoke` + `_streamIterator`), which every provider class inherits, so a single module covers all providers. The listener injects the Sentry callback handler into the call options, and LangChain's own callback dispatch creates the spans exactly as before, so the span output is identical. Embeddings have no shared base method, so they're hooked per provider (`@langchain/openai` for now) and get their span via `bindTracingChannelToSpan`, reusing the same core span builder as the OTel path. The OTel path stays as the fallback when orchestrion isn't injected. The existing node-integration suite runs against both paths under `INJECT_ORCHESTRION`, proving parity for langchain v0.3 and v1.
The OTel path covered 6 chat provider packages; chat is already handled by the single @langchain/core BaseChatModel hook. For embeddings (the per-package surface), wire the packages that ship an Embeddings subclass: openai, google-genai, mistralai, and google-vertexai (whose methods live on the shared @langchain/google-common base). anthropic and groq are chat-only. The embeddings channel list is derived from the provider list so adding a provider is a single edit.
…sted duplicate span
0e63ac1 to
62c6eb6
Compare


Rewrites the LangChain integration to a
node:diagnostics_channellistener instead ofInstrumentationBase, with orchestrion injecting the channels. Follows the OpenAI/Anthropic/dataloader pattern; the vendored OTel path stays as the fallback when orchestrion isn't injected.Some decisions due to some differences with other integrations:
auto.ai.langchain(spans come from the shared core handler/builder, not the subscriber). The dual-mode test still catches broken selectors: under orchestrion the OTel integration is filtered out, so wrong selectors yield zero spans.embedQuery/embedDocumentscall the SDK internally.@langchain/corerange>=0.1.0 <2.0.0covers langchain v0.3 and v1.closes #20915